package com.xia.netty.thread.aqs;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * 自定义同步器
 */
public class AQSDemo2 {
    //AQS同步接口
    private Sync sync;

    public AQSDemo2() {
        sync = new Sync();
    }

    public void lock() {
        sync.acquire(1);
    }

    public void unlock() {
        sync.release(1);
    }

    public void show() {
        sync.showLockThread();
    }

    class Sync extends AbstractQueuedSynchronizer {

        @Override
        protected boolean tryAcquire(int arg) {
            //获取当前线程
            final Thread thread = Thread.currentThread();
            //获取状态 默认值0 没有加锁
            int state = getState();
            if (state == 0) {
                //设置锁的状态
                if (compareAndSetState(0, arg)) {
                    //将当前线程设置成锁的拥有者
                    setExclusiveOwnerThread(thread);
                    return true;
                }
            } else if (thread == getExclusiveOwnerThread()) {//判断获取锁的线程是否是当前持有锁的线程(可重入)
                int next = state + arg;
                setState(next);
                return true;
            }

            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            //获取当前线程
            Thread thread = Thread.currentThread();
            int state = getState() - arg;
            //判断当前线程是否是持有锁的线程
            if (thread != getExclusiveOwnerThread()) {
                throw new IllegalMonitorStateException();
            }
            boolean free = false;
            if (state == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(state);
            return free;
        }

        public void showLockThread() {
            if (getExclusiveOwnerThread() != null) {
                System.out.println("持有锁的线程为:" + getExclusiveOwnerThread().getName());
            }
        }

    }

    public static void main(String[] args) throws InterruptedException {
        AQSDemo2 aqsDemo2 = new AQSDemo2();
        Thread t1 = new Thread(() -> {
            System.out.println("t1 start");
            aqsDemo2.lock();
            try {
                System.out.println("t1 getLock");
                Thread.sleep(5000);
//                aqsDemo2.lock();
//                System.out.println("t1 get lock again");
                System.out.println("t1 return");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                aqsDemo2.unlock();
            }
        });
        t1.setName("T1");

        Thread t2 = new Thread(() -> {
            System.out.println("t2 start");
            aqsDemo2.lock();
            try {
                System.out.println("t2 getLock");
                Thread.sleep(5000);
                System.out.println("t2 return");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                aqsDemo2.unlock();
            }
        });
        t2.setName("T2");

        t1.start();
        t2.start();
        // ?
        Thread.sleep(2000);

        aqsDemo2.show();
        //挂起当前线程,执行子线程  保证子线程在主线程结束前运行完成
        t1.join();
        t2.join();

        System.out.println("main end");

    }

}

